<?php

namespace server\dao;

use common\core\validators\MobileValidator;
use common\helpers\BaseHelper;
use common\helpers\CodeHelper;
use common\helpers\ConstantHelper;
use common\helpers\DictHelper;
use Yii;
use yii\db\Query;
use yii\helpers\ArrayHelper;
use yii\web\IdentityInterface;

/**
 * This is the model class for table "{{%user}}".
 *
 * @property integer $id
 * @property string  $username
 * @property string  $auth_key
 * @property string  $password_hash
 * @property string  $mobile
 * @property integer $gender
 * @property string  $email
 * @property string  $head_thumb
 * @property integer $status
 * @property integer $created_at
 * @property integer $updated_at
 */
class User extends \common\core\server\ActiveRecord implements IdentityInterface
{

    public static $isApi;

    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return '{{%user}}';
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        $gender = DictHelper::getGenderType(false);
        $gender = array_keys($gender);
        return [
            [['gender', 'status', 'created_at', 'updated_at'], 'integer'],
            [['username', 'auth_key','line_ids'], 'string', 'max' => 32],
            [['password_hash'], 'string', 'max' => 60, 'min' => 6],
            [['mobile'], 'string', 'max' => 15],
            [['email', 'head_thumb'], 'string', 'max' => 255],
            //[['email'], 'email'],
            [['mobile'], MobileValidator::className()],
            ['gender', 'in', 'range' => $gender],
            ['gender', 'default', 'value' => 0],
            ['auth_key', 'default', 'value' => \Yii::$app->security->generateRandomString(16)],
            [['username', 'password_hash'], 'required', 'on' => 'login'],
            [['password_hash'], 'validatePasswordLogin', 'on' => 'login'],
            [['username'], 'required', 'on' => 'register'],
            [['username', 'mobile', 'email'], 'unique', 'on' => 'register'],
            ['password_hash', 'validateEditRequired', 'on' => 'register', 'skipOnEmpty' => false],
            [
                'password_hash',
                'filter',
                'filter' => function () {
                    return !empty($this->password_hash) ? \Yii::$app->security->generatePasswordHash($this->password_hash) : $this->oldAttributes['password_hash'];
                },
                'on'     => ['register', 'resetPassword', 'changePassword'],
            ],
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'id'         => 'ID',
            'username'    => '账号',
            'auth_key'   => 'Auth Key',
            'password_hash'   => '密码',
            'line_ids'   => '所属线路集合 1，2',
            'mobile'     => '手机号',
            'gender'     => '性别',
            'email'      => '邮箱',
            'head_thumb' => '头像',
            'status'     => '状态',
            'created_at' => '创建时间',
            'updated_at' => '更新时间',
        ];
    }

    public function validateEditRequired($attribute, $params)
    {
        if (!$this->id && empty($this->password_hash)) {
            $this->addError($attribute, '密码不能为空.');
        }
    }

    /**
     * Validates the password.
     * This method serves as the inline validation for password.
     *
     * @param string $attribute the attribute currently being validated
     * @param array  $params    the additional name-value pairs given in the rule
     */
    public function validatePasswordLogin($attribute, $params)
    {
        if (!$this->hasErrors()) {
            $user = $this->getUserOne(['username' => $this->username]);
            if (!$user || !$user->validatePassword($this->password_hash)) {
                $this->addError($attribute, '无效账号或密码.');
            }
        }
    }

    /**
     * Validates password
     *
     * @param string $password password to validate
     * @return bool if password provided is valid for current user
     */
    public function validatePassword($password)
    {
        return Yii::$app->security->validatePassword($password, $this->password_hash);
    }

    /**
     * Finds an identity by the given ID.
     *
     * @param int|string $id
     *
     * @return array|null|\yii\db\ActiveRecord|IdentityInterhead_thumb
     * the ID to be looked for the identity object that matches the given ID.
     * Null should be returned if such an identity cannot be found
     * or the identity is not in an active state (disabled, deleted, etc.)
     */
    public static function findIdentity($id)
    {
        return self::find()->where([
            'id'        => $id,
            'status' => ConstantHelper::NOT_DELETE,
        ])->one();
    }

    /**
     * Finds an identity by the given token.
     *
     * @param mixed $token the token to be looked for
     * @param mixed $type  the type of the token. The value of this parameter depends on the implementation.
     *                     For example, [[\yii\filters\auth\HttpBearerAuth]] will set this parameter to be `yii\filters\auth\HttpBearerAuth`.
     *
     * @return IdentityInterhead_thumb the identity object that matches the given token.
     * Null should be returned if such an identity cannot be found
     * or the identity is not in an active state (disabled, deleted, etc.)
     *
     * @throws \yii\base\UserException
     */
    public static function findIdentityByAccessToken($token, $type = null)
    {
        $userToken = (new UserToken())->getUserToken([
            'token'  => $token,
            'app_id' => Yii::$app->id,
        ]);
        // 是否有效
        if (empty($userToken)) {
            BaseHelper::invalidException(CodeHelper::TOKEN_INVALID, CodeHelper::getCodeText(CodeHelper::TOKEN_INVALID));
        }
        // 是否 过期
        if ($userToken->expires_in < time()) {
            BaseHelper::invalidException(CodeHelper::TOKEN_EXPIRES, CodeHelper::getCodeText(CodeHelper::TOKEN_EXPIRES));
        }
        // 是否其他地方登录
        if ($userToken->forced_offline == 1) {
            BaseHelper::invalidException(CodeHelper::TOKEN_OFFLINE, CodeHelper::getCodeText(CodeHelper::TOKEN_OFFLINE));
        }
        self::$isApi = ArrayHelper::getValue(Yii::$app->params, 'isApi', true);
        return self::findIdentity($userToken->user_id);
    }

    /**
     * Returns an ID that can uniquely identify a user identity.
     * @return string|int an ID that uniquely identifies a user identity.
     */
    public function getId()
    {
        return $this->getPrimaryKey();
    }

    /**
     * Returns a key that can be used to check the validity of a given identity ID.
     *
     * The key should be unique for each individual user, and should be persistent
     * so that it can be used to check the validity of the user identity.
     *
     * The space of such keys should be big enough to defeat potential identity attacks.
     *
     * This is required if [[User::enableAutoLogin]] is enabled.
     * @return string a key that is used to check the validity of a given identity ID.
     * @see validateAuthKey()
     */
    public function getAuthKey()
    {
        return $this->auth_key;
    }

    /**
     * Validates the given auth key.
     *
     * This is required if [[User::enableAutoLogin]] is enabled.
     *
     * @param string $authKey the given auth key
     *
     * @return bool whether the given auth key is valid.
     * @see getAuthKey()
     */
    public function validateAuthKey($authKey)
    {
        return $this->getAuthKey() === $authKey;
    }

    /**
     * 用户查询条件
     *
     * @param Query $model
     * @param array $params
     *
     * @return Query
     */
    private function getUserWhere(Query $model, array $params)
    {

        if ($this->issetAndEmpty($params, 'id')) {
            $model->andWhere(['id' => $params['id']]);
        }

        if ($this->issetAndEmpty($params, 'username')) {
            $model->andWhere(['username' => $params['username']]);
        }

        if ($this->issetAndEmpty($params, 'type', true)) {
            $model->andWhere(['type' => $params['type']]);
        }

        if ($this->issetAndEmpty($params, 'created_at')) {
            $time = BaseHelper::formattingDoubleDate($params['created_at']);
            $model->andWhere(['between', 'created_at', $time[0], $time[1]]);
        }
        return $model;
    }

    /**
     * 获得用户列表
     *
     * @param array $params [
     *                      'username',
     *                      'mobile',
     *                      'gender',
     *                      'email',
     *                      'created_at',
     *                      'updated_at',
     *                      ]
     *
     * @param bool  $isAll
     *
     * @return array
     */
    public function getUserList(array $params, $isAll = false)
    {
        $model = new Query();
        $model->select([
            'id',
            'username',
            'mobile',
            'gender',
            'email',
            'head_thumb',
            'created_at',
            'updated_at',
            'line_ids',
        ])->from($this->tableName())->where(['status' => ConstantHelper::NOT_DELETE ]);
        $model ->andWhere(['<>','username','admin']);
        $model = $this->getUserWhere($model, $params);
        $this->order($model);
        return $isAll ? $model->all() : $this->page($model);
    }

    /**
     * 获得 一个 用户数据
     *
     * @param array $params
     *
     * @return mixed
     */
    public function getUserOne(array $params)
    {
        $model = $this->find()->from($this->tableName())->where(['status' => ConstantHelper::NOT_DELETE]);
        return $this->getUserWhere($model, $params)->one();
    }

    /**
     * 注册
     *
     * @param array $params [
     *                      'username',
     *                      'mobile',
     *                      'gender',
     *                      'email',
     *                      'head_thumb',
     *                      ]
     *
     * @param bool  $isApi  是否api
     *
     * @return array|mixed
     * @throws \yii\base\Exception
     */
    public function register(array $params, $isApi = false)
    {
        $user = new User();
        if ($this->isAddRecord && $this->issetAndEmpty($params, 'id', true)) {
            $user = $this->findIdentity($params['id']);
            if (empty($user)) {
                $this->invalidParamException($this->table() . '不存在');
            }
        }

        $data = $this->filterParams($params);

        $user->scenario = 'register';
        $user->setAttributes($data);
        $user->save($isApi);
        return $user;
    }

    /**
     * table name
     *
     * @return mixed
     */
    public function table()
    {
        return '账号';
    }
}
